home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / auth / part02 < prev    next >
Encoding:
Internet Message Format  |  1990-04-29  |  51.9 KB

  1. Subject:  v22i002:  RFC931 TCP Authentication server, Part02/02
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 18bc6a4c 9c051008 1e57a113 534ecf48
  5.  
  6. Submitted-by: Dan Bernstein <brnstnd@acf10.nyu.edu>
  7. Posting-number: Volume 22, Issue 2
  8. Archive-name: auth2.1/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 2 (of 2)."
  17. # Contents:  attachport.c authtcp.c rfc931
  18. # Wrapped by rsalz@litchi.bbn.com on Mon Apr 30 15:53:40 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'attachport.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'attachport.c'\"
  22. else
  23. echo shar: Extracting \"'attachport.c'\" \(20921 characters\)
  24. sed "s/^X//" >'attachport.c' <<'END_OF_FILE'
  25. X/*
  26. Xattachport.c: attach a server program to a TCP port
  27. X*/
  28. X
  29. X/* WARNING! WARNING! WARNING! */
  30. X/* For the authentication to work, attachport must run setuid auth! */
  31. X/* All setuid programs are dangerous! Check them carefully! */
  32. X
  33. Xstatic char attachportauthor[] =
  34. X"attachport was written by Daniel J. Bernstein.\n\
  35. XInternet address: brnstnd@acf10.nyu.edu.\n";
  36. X
  37. Xstatic char attachportversion[] = 
  38. X"attachport version 4.1, April 18, 1990.\n\
  39. XCopyright (c) 1990, Daniel J. Bernstein.\n\
  40. XAll rights reserved.\n";
  41. X
  42. Xstatic char attachportcopyright[] =
  43. X"attachport version 4.1, April 18, 1990.\n\
  44. XCopyright (c) 1990, Daniel J. Bernstein.\n\
  45. XAll rights reserved.\n\
  46. X\n\
  47. XUntil January 1, 1995, you are granted the following rights: A. To make\n\
  48. Xcopies of this work in original form, so long as (1) the copies are exact\n\
  49. Xand complete; (2) the copies include the copyright notice, this paragraph,\n\
  50. Xand the disclaimer of warranty in their entirety. B. To distribute this\n\
  51. Xwork, or copies made under the provisions above, so long as (1) this is\n\
  52. Xthe original work and not a derivative form; (2) you do not charge a fee\n\
  53. Xfor copying or for distribution; (3) you ensure that the distributed form\n\
  54. Xincludes the copyright notice, this paragraph, and the disclaimer of\n\
  55. Xwarranty in their entirety. These rights are temporary and revocable upon\n\
  56. Xwritten, oral, or other notice by Daniel J. Bernstein. These rights are\n\
  57. Xautomatically revoked on January 1, 1995. This copyright notice shall be\n\
  58. Xgoverned by the laws of the state of New York.\n\
  59. X\n\
  60. XIf you have questions about attachport or about this copyright notice,\n\
  61. Xor if you would like additional rights beyond those granted above,\n\
  62. Xplease feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  63. Xon the Internet.\n";
  64. X
  65. Xstatic char attachportwarranty[] =
  66. X"To the extent permitted by applicable law, Daniel J. Bernstein disclaims\n\
  67. Xall warranties, explicit or implied, including but not limited to the\n\
  68. Ximplied warranties of merchantability and fitness for a particular purpose.\n\
  69. XDaniel J. Bernstein is not and shall not be liable for any damages,\n\
  70. Xincidental or consequential, arising from the use of this program, even\n\
  71. Xif you inform him of the possibility of such damages. This disclaimer\n\
  72. Xshall be governed by the laws of the state of New York.\n\
  73. X\n\
  74. XIn other words, use this program at your own risk.\n\
  75. X\n\
  76. XIf you have questions about attachport or about this disclaimer of warranty,\n\
  77. Xplease feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  78. Xon the Internet.\n";
  79. X
  80. Xstatic char attachportusage[] =
  81. X"Usage: attachport [ -01vrRxXACHUVW ] [ -pport ] program [ arg ... ]\n\
  82. XHelp:  attachport -H\n";
  83. X
  84. Xstatic char attachporthelp[] =
  85. X"attachport attaches a server program to a TCP port.\n\
  86. X\n\
  87. Xattachport -A: print authorship notice\n\
  88. Xattachport -C: print copyright notice\n\
  89. Xattachport -H: print this notice\n\
  90. Xattachport -U: print short usage summary\n\
  91. Xattachport -V: print version number\n\
  92. Xattachport -W: print disclaimer of warranty\n\
  93. X\n\
  94. Xattachport [ -01vrRxX ] [ -pport ] program [ arg ... ]: attach program to port\n\
  95. X  -v: verbose: proclaim success\n\
  96. X  -1: print port number on standard output\n\
  97. X  -0: check every ten seconds for fd 0 to have links; if none, wither away\n\
  98. X  -x: locally authenticate connections with authd(8) (default)\n\
  99. X  -X: do not locally authenticate\n\
  100. X  -r: attempt to authenticate the remote side as well (default), placing\n\
  101. X      user@host and TCP into environment variables REMOTE and PROTO\n\
  102. X  -R: do not remotely authenticate\n\
  103. X  -pport: attach server to a particular TCP port\n\
  104. X\n\
  105. XIf you have questions about or suggestions for attachport, please feel free\n\
  106. Xto contact the author, Daniel J. Bernstein, at brnstnd@acf10.nyu.edu\n\
  107. Xon the Internet.\n";
  108. X
  109. X#include <stdio.h>
  110. X#include <sys/types.h>
  111. X#include <sys/file.h>
  112. X#ifdef BSD
  113. X#include <limits.h>
  114. X#endif
  115. X#include <sys/ioctl.h>
  116. X#include <sys/socket.h>
  117. X#include <sys/time.h>
  118. X#include <sys/wait.h>
  119. X#include <sys/resource.h>
  120. X#include <sys/stat.h>
  121. X#include <netinet/in.h>
  122. X#include <arpa/inet.h>
  123. X#include <netdb.h>
  124. X#include <signal.h>
  125. X#include <sys/param.h>
  126. X#include <pwd.h>
  127. Xextern char *malloc(); /* many systems don't have malloc.h */
  128. Xextern int getopt();
  129. Xextern char *optarg; /* these should be in getopt.h! */
  130. Xextern int optind;
  131. X#include <ctype.h>
  132. X#include "authuser.h"
  133. X#include "djberr.h"
  134. X#include "djbatoi.h"
  135. X
  136. X#ifndef AUTHDIR
  137. X#define AUTHDIR "/usr/etc/auth"
  138. X#endif
  139. X
  140. X#ifndef MAXHOSTNAMELEN
  141. X#define MAXHOSTNAMELEN 128 /* stupid Suns don't define this in sys/param.h */
  142. X#endif
  143. X
  144. Xint numkids = 0;
  145. Xint flagauth = 1;
  146. X
  147. Xunsigned long myinetaddr()
  148. X{
  149. X char hn[MAXHOSTNAMELEN + 1];
  150. X struct hostent *he;
  151. X
  152. X if (gethostname(hn,MAXHOSTNAMELEN) == -1)
  153. X   return((unsigned long) -1);
  154. X if ((he = gethostbyname(hn)) == NULL)
  155. X   return((unsigned long) -1);
  156. X
  157. X return (*((unsigned long *) (he->h_addr)));
  158. X}
  159. X
  160. Xdissociatetty()
  161. X{
  162. X int fd;
  163. X
  164. X if ((fd = open("/dev/tty",O_RDWR)) == -1)
  165. X  {
  166. X   perrn2("%s","attachport: warning: cannot open /dev/tty");
  167. X  }
  168. X else
  169. X  {
  170. X   if (ioctl(fd,(unsigned long) TIOCNOTTY,(char *) NULL) == -1)
  171. X     perrn2("%s","attachport: warning: cannot dissociate /dev/tty");
  172. X   (void) close(fd);
  173. X  }
  174. X}
  175. X
  176. Xint uid;
  177. Xint euid;
  178. X
  179. Xint flagcheckin = 0;
  180. Xint alrmcounter = 0;
  181. X
  182. Xint flagdie;
  183. X
  184. Xsigterm()
  185. X{
  186. X flagdie = 1;
  187. X}
  188. X
  189. Xsigalrm()
  190. X{
  191. X struct stat st;
  192. X
  193. X if (flagcheckin)
  194. X  {
  195. X   (void) fstat(0,&st);
  196. X   if (st.st_nlink == 0)
  197. X     sigterm();
  198. X  }
  199. X if ((++alrmcounter) % 12) /* every two minutes */
  200. X  {
  201. X   alrmcounter = 0;
  202. X   (void) kill(getpid(),SIGCHLD);
  203. X  }
  204. X}
  205. X
  206. Xsigchld()
  207. X{
  208. X int w;
  209. X char authfn[sizeof(AUTHDIR) + 30];
  210. X char authpfn[sizeof(AUTHDIR) + 30];
  211. X int authpfd;
  212. X int r;
  213. X int noweuid = geteuid();
  214. X
  215. X if (noweuid == uid) /* oopsie */
  216. X   if (setreuid(uid,euid))
  217. X    {
  218. X     perrn2("%s","attachport: warning: cannot setreuid");
  219. X     return; /* This is impossible anyway. */
  220. X    }
  221. X
  222. X while ((w = wait3((union wait *) 0,WNOHANG,(struct rusage *) NULL)) > 0)
  223. X  {
  224. X   numkids--;
  225. X   if (flagauth)
  226. X    {
  227. X     (void) sprintf(authpfn,"%s/tcp/ps.%d.%d",AUTHDIR,getpid(),w);
  228. X     if ((authpfd = open(authpfn,O_RDONLY,0600)) == -1)
  229. X      {
  230. X       perrn2("attachport: warning: cannot unlink authentication entry %s",authpfn);
  231. X       continue;
  232. X      }
  233. X     r = read(authpfd,authfn,sizeof(authfn));
  234. X     (void) close(authpfd);
  235. X     if ((r <= 0) || (strncmp(authfn,AUTHDIR,strlen(AUTHDIR))))
  236. X      { /* Make sure the worst damage we can do is confined to AUTHDIR. */
  237. X       perrn2("attachport: warning: cannot unlink authentication entry %s",authpfn);
  238. X       continue;
  239. X      }
  240. X     authfn[r] = '\0';
  241. X     if (unlink(authfn) == -1) /* had better succeed! */
  242. X      {
  243. X       perrn2("attachport: warning: cannot unlink authentication entry %s",authfn);
  244. X       continue;
  245. X      }
  246. X     if (unlink(authpfn) == -1) /* had better succeed! */
  247. X      {
  248. X       perrn2("attachport: warning: cannot unlink authentication entry %s",authpfn);
  249. X      }
  250. X    }
  251. X  }
  252. X
  253. X if (noweuid == uid) /* daisie */
  254. X   if (setreuid(euid,uid))
  255. X    {
  256. X     perrn2("%s","attachport: warning: cannot setreuid");
  257. X     return;
  258. X    }
  259. X}
  260. X
  261. Xextern char **environ;
  262. X
  263. Xmain(argc,argv,envp)
  264. Xint argc;
  265. Xchar *argv[];
  266. Xchar *envp[];
  267. X{
  268. X int opt;
  269. X int flagverbose = 0;
  270. X int flagminiverb = 0;
  271. X int flagremote = 2;
  272. X char *strlocalport = "0";
  273. X unsigned short localport;
  274. X char **program = NULL;
  275. X struct sockaddr_in sa;
  276. X int s;
  277. X int t;
  278. X unsigned long in;
  279. X int dummy;
  280. X struct passwd *pw;
  281. X int f;
  282. X int authfd;
  283. X int authpfd;
  284. X char authfn[sizeof(AUTHDIR) + 30];
  285. X char authpfn[sizeof(AUTHDIR) + 30];
  286. X char lockfn[sizeof(AUTHDIR) + 30];
  287. X int lockfd;
  288. X char lockbuf[32]; /* 5 pid, 1 :, 10 I, 1 ., 5 R, 1 \n, 8 U, 1\0 */
  289. X           /* we use just 5 pid, 1 -, 8 U, 1\0 */
  290. X int lockbuflen;
  291. X char foobuf[32];
  292. X struct itimerval it;
  293. X fd_set ready;
  294. X struct servent *se;
  295. X struct in_addr inet; /* dummy for inet_ntoa */
  296. X int flagsigintign;
  297. X int flagsigquitign;
  298. X int flagsigtstpign;
  299. X int flagsighupign;
  300. X int flagsigxcpuign;
  301. X int flagsigxfszign;
  302. X int flagsigvtalrmign;
  303. X int flagsigprofign;
  304. X int flagsigchldign;
  305. X int flagsigalrmign;
  306. X int flagsigtermign;
  307. X
  308. X /* ALERT! ALERT! ALERT! We're probably running setuid auth! */
  309. X /* Note that accounting is by real uid, not effective uid. */
  310. X /* The system should be careful about setuid core dumps 'n' such. */
  311. X
  312. X uid = getuid();
  313. X euid = geteuid();
  314. X
  315. X /* The following are necessary to be absolutely sure of removing the
  316. X    authentication entry. It's a flaw of the signal handling system that
  317. X    every new extension could turn a secure program like this into an
  318. X    (ever so slightly) insecure one. */
  319. X flagsigintign = (signal(SIGINT,SIG_IGN) == SIG_IGN);
  320. X flagsigquitign = (signal(SIGQUIT,SIG_IGN) == SIG_IGN);
  321. X flagsigtstpign = (signal(SIGTSTP,SIG_IGN) == SIG_IGN);
  322. X flagsighupign = (signal(SIGHUP,SIG_IGN) == SIG_IGN);
  323. X flagsigxcpuign = (signal(SIGXCPU,SIG_IGN) == SIG_IGN);
  324. X flagsigxfszign = (signal(SIGXFSZ,SIG_IGN) == SIG_IGN);
  325. X flagsigvtalrmign = (signal(SIGVTALRM,SIG_IGN) == SIG_IGN);
  326. X flagsigprofign = (signal(SIGPROF,SIG_IGN) == SIG_IGN);
  327. X flagsigchldign = (signal(SIGCHLD,SIG_IGN) == SIG_IGN);
  328. X flagsigalrmign = (signal(SIGALRM,SIG_IGN) == SIG_IGN);
  329. X flagsigtermign = (signal(SIGTERM,SIG_IGN) == SIG_IGN);
  330. X /* At least we can depend on SIG_IGN and SIG_DFL being the only
  331. X    possible handlers passed through an exec. Programmers should note
  332. X    the above trick to avoid having to worry about the signal() type. */
  333. X
  334. X while ((opt = getopt(argc,argv,"01vrRxXp:ACHUVW")) != EOF)
  335. X   switch(opt)
  336. X    {
  337. X     case 'v': flagverbose = 1; break;
  338. X     case '1': flagminiverb = 1; break;
  339. X     case '0': flagcheckin = 1; break;
  340. X     case 'r': flagremote = 1; break;
  341. X     case 'R': flagremote = 0; break;
  342. X     case 'x': flagauth = 1; break;
  343. X     case 'X': flagauth = 0; break;
  344. X     case 'p': strlocalport = optarg; break;
  345. X     case 'A': (void) err(attachportauthor);(void)setreuid(uid,uid); exit(1);
  346. X     case 'C': (void) err(attachportcopyright);(void)setreuid(uid,uid); exit(1);
  347. X     case 'H': (void) err(attachporthelp);(void)setreuid(uid,uid); exit(1);
  348. X     case 'U': (void) err(attachportusage);(void)setreuid(uid,uid); exit(1);
  349. X     case 'V': (void) err(attachportversion);(void)setreuid(uid,uid); exit(1);
  350. X     case 'W': (void) err(attachportwarranty);(void)setreuid(uid,uid); exit(1);
  351. X     case '?': (void) err(attachportusage);(void)setreuid(uid,uid); exit(1);
  352. X    }
  353. X argv += optind; argc -= optind;
  354. X program = argv;
  355. X
  356. X if ((program == NULL) || (*program == NULL))
  357. X  {
  358. X   (void) err(attachportusage);
  359. X   (void) setreuid(uid,uid); exit(1);
  360. X  }
  361. X
  362. X in = myinetaddr();
  363. X if (in == (unsigned long) -1)
  364. X  {
  365. X   (void) errn("attachport: fatal: can't find my own Internet number?!");
  366. X   (void) setreuid(uid,uid); exit(1);
  367. X  }
  368. X
  369. X t = strlen(strlocalport) - 1;
  370. X if (isascii(strlocalport[t]) && isdigit(strlocalport[t]))
  371. X   localport = atoi(strlocalport); /* so who cares if it's zero? */
  372. X else
  373. X   if ((se = getservbyname(strlocalport,"tcp")) == NULL)
  374. X     localport = 0;
  375. X   else
  376. X     localport = ntohs(se->s_port); /* inconsistency alert! */
  377. X                    /* se->s_port is int! */
  378. X
  379. X if (flagauth)
  380. X   if ((pw = getpwuid(uid)) == NULL)
  381. X    {
  382. X     (void) errn("attachport: fatal: cannot authenticate: who are you?");
  383. X     (void) setreuid(uid,uid); exit(1);
  384. X    }
  385. X
  386. X /* We now switch to the real user id, though preserving euid for auth. */
  387. X
  388. X if (setreuid(euid,uid))
  389. X  {
  390. X   perrn2("%s","attachport: fatal: cannot setreuid");
  391. X   (void) setreuid(uid,uid); exit(1);
  392. X  }
  393. X
  394. X if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) /* no security problem */
  395. X  {
  396. X   perrn2("%s","attachport: fatal: cannot create socket");
  397. X   (void) setreuid(uid,uid); exit(1);
  398. X  }
  399. X
  400. X sa.sin_family = AF_INET;
  401. X sa.sin_port = htons(localport);
  402. X sa.sin_addr.s_addr = INADDR_ANY;
  403. X
  404. X if (bind(s,&sa,sizeof(sa)) == -1)
  405. X  {
  406. X   perrn2("%s","attachport: fatal: cannot bind");
  407. X   (void) setreuid(uid,uid); exit(1);
  408. X  }
  409. X
  410. X if (listen(s,5) == -1) /* 5 should be an option! */
  411. X  {
  412. X   perrn2("%s","attachport: fatal: cannot listen");
  413. X   (void) setreuid(uid,uid); exit(1);
  414. X  }
  415. X
  416. X dissociatetty();
  417. X
  418. X (void) signal(SIGTERM,sigterm); /* for killaport */
  419. X (void) signal(SIGALRM,sigalrm); /* used to be just if flagcheckin */
  420. X it.it_value.tv_sec = 10; it.it_value.tv_usec = 0; /* every ten seconds */
  421. X it.it_interval.tv_sec = 10; it.it_interval.tv_usec = 0;
  422. X (void) setitimer(ITIMER_REAL,&it,(struct itimerval *) 0);
  423. X
  424. X /* we still have uids switched */
  425. X if (setreuid(uid,euid))
  426. X  {
  427. X   perrn2("%s","attachport: fatal: cannot setreuid");
  428. X   (void) setreuid(uid,uid); exit(1);
  429. X  }
  430. X /* Now we're back to setuid auth... */
  431. X
  432. X dummy = sizeof(sa);
  433. X if (getsockname(s,&sa,&dummy) == -1)
  434. X  {
  435. X   perrn2("%s","attachport: fatal: cannot get socket name");
  436. X   (void) setreuid(uid,uid); exit(1);
  437. X  }
  438. X if (flagremote == 2)
  439. X   flagremote = (ntohs(sa.sin_port) != 113);
  440. X if (flagverbose)
  441. X   (void) errn2("attachport: attached to port %d",ntohs(sa.sin_port));
  442. X if (flagminiverb)
  443. X  {
  444. X   (void) printf("%d\n",ntohs(sa.sin_port));
  445. X   (void) fflush(stdout);
  446. X  }
  447. X if (flagauth)
  448. X  {
  449. X   (void) sprintf(lockfn,"%s/tcp/lock.%u",AUTHDIR,
  450. X          (unsigned int) ntohs(sa.sin_port));
  451. X   if (((lockfd = open(lockfn,O_WRONLY | O_CREAT | O_EXCL,0600)) == -1)
  452. X     &&(((lockfd = open(lockfn,O_RDONLY)) == -1)
  453. X    ||(flock(lockfd,LOCK_EX) == -1)
  454. X        ||(read(lockfd,lockbuf,31) <= 0)
  455. X    ||((lockbuf[0] != '!')
  456. X          &&((atoi(lockbuf) <= 0)
  457. X             ||(kill(atoi(lockbuf),0) == 0))) /* okay, screw the last process */
  458. X    ||(close(lockfd) == -1) /* impossible */
  459. X        ||((lockfd = open(lockfn,O_WRONLY | O_CREAT | O_TRUNC,0600)) == -1)))
  460. X    { /* yikes, that was incomprehensible */
  461. X     errn2("attachport: fatal: local port %u locked",
  462. X       (unsigned int) ntohs(sa.sin_port));
  463. X     (void) setreuid(uid,uid); exit(1);
  464. X    }
  465. X   (void) flock(lockfd,LOCK_EX);
  466. X   (void) sprintf(lockbuf,"%d-%s",getpid(),pw->pw_name);
  467. X   lockbuflen = strlen(lockbuf);
  468. X   (void) sprintf(foobuf,"!%s%d",pw->pw_name,getpid());
  469. X   (void) write(lockfd,lockbuf,lockbuflen);
  470. X   (void) flock(lockfd,LOCK_UN);
  471. X  }
  472. X
  473. X /* We must remain setuid auth as long as there are live authentication */
  474. X /* entries. Otherwise the user could kill us and, if lucky enough, */
  475. X /* misauthenticate future connections. It isn't so important to worry */
  476. X /* about the lock file: that can only lead to a denial of service, and */
  477. X /* it would take a huge amount of effort to guarantee that denial. */
  478. X /* Anyway, we have to fork as the real uid: one system stupidity is */
  479. X /* that fork() uses the effective uid for MAXUPRC checks. This isn't */
  480. X /* a problem if there are no live authentication entries. */
  481. X
  482. X /* The solution is simple: We screw up the lock file while forking as */
  483. X /* the real uid, then restore it afterwards. If we're killed in the */
  484. X /* middle, authd will notice. This once again reduces the problem to */
  485. X /* denial of service, which is acceptable. (In fact, the nature of the */
  486. X /* messed up lock file is that it can't even cause denial of service.) */
  487. X /* Ha! */
  488. X
  489. X (void) signal(SIGCHLD,sigchld);
  490. X for (;;)
  491. X   if (flagdie)
  492. X     if (numkids > 0)
  493. X       sleep(60);
  494. X     else
  495. X      {
  496. X       if (flagauth)
  497. X     (void) unlink(lockfn);
  498. X       (void) setreuid(uid,uid); exit(0); /* ahhh, so simple */
  499. X      }
  500. X   else
  501. X    {
  502. X     FD_ZERO(&ready); /* why, oh why doesn't this pass lint? */
  503. X     FD_SET(s,&ready);
  504. X     while ((select(s + 1,&ready,(fd_set *) 0,(fd_set *) 0,0) < 0)
  505. X        && !flagdie)
  506. X       ; /* on error, ready won't be affected, so this is safe */
  507. X     if (!flagdie) /* could be set any time, so we have to check */
  508. X      {
  509. X       dummy = sizeof(sa);
  510. X       (void) flock(lockfd,LOCK_EX);
  511. X       (void) lseek(lockfd,(off_t) 0,0);
  512. X       (void) write(lockfd,foobuf,lockbuflen);
  513. X       if ((t = accept(s,&sa,&dummy)) > -1)
  514. X         if (setreuid(euid,uid))
  515. X      {
  516. X       perrn2("%s","attachport: warning: cannot setreuid");
  517. X       (void) setreuid(uid,euid);
  518. X      }
  519. X         else if ((f = fork()) == 0)
  520. X          {
  521. X           if (setreuid(uid,euid))
  522. X            {
  523. X             perrn2("%s","attachport: fatal: cannot setreuid");
  524. X             (void) setreuid(uid,uid); exit(1);
  525. X            }
  526. X           if (flagauth)
  527. X            {
  528. X             (void) sprintf(authfn,"%s/tcp/%D.%d.%d",AUTHDIR,
  529. X                            sa.sin_addr.s_addr,localport,ntohs(sa.sin_port));
  530. X             (void) sprintf(authpfn,"%s/tcp/ps.%d.%d",AUTHDIR,getppid(),getpid());
  531. X           if ((authpfd = open(authpfn,O_WRONLY | O_CREAT | O_EXCL,0600)) == -1)
  532. X            {
  533. X               perrn2("%s","attachport: warning: cannot authenticate");
  534. X          }
  535. X             if ((authfd = open(authfn,O_WRONLY | O_CREAT | O_EXCL,0600)) == -1)
  536. X              {
  537. X               perrn2("%s","attachport: warning: cannot authenticate");
  538. X              }
  539. X             (void) write(authpfd,authfn,strlen(authfn));
  540. X             (void) write(authfd,pw->pw_name,strlen(pw->pw_name));
  541. X             (void) close(authpfd);
  542. X             (void) close(authfd); /* if it fails, tough luck. */
  543. X            }
  544. X
  545. X           if (flagremote)
  546. X            {
  547. X             unsigned long in; /* keep confirming variables separate */
  548. X             unsigned short local;
  549. X             unsigned short remote;
  550. X             char *ruser;
  551. X             char *srem;
  552. X             char **temp;
  553. X             char **trem;
  554. X             char **tproto;
  555. X             char **envbak;
  556. X        
  557. X             if (auth_fd(t,&in,&local,&remote) == -1)
  558. X              {
  559. X               perrn2("%s","attachport: fatal: cannot confirm connection");
  560. X               exit(1);
  561. X              }
  562. X             if ((ruser = auth_tcpuser(in,local,remote)) == NULL)
  563. X               ruser = ""; /* bummer */
  564. X             if ((srem = malloc(strlen(ruser) + 30)) == NULL)
  565. X              {
  566. X               perrn2("%s","attachport: fatal: cannot allocate environment");
  567. X               exit(1);
  568. X              }
  569. X         inet.s_addr = in;
  570. X         sprintf(srem,"REMOTE=%s@%s",ruser,inet_ntoa(inet));
  571. X             for (trem = envp;*trem;trem++)
  572. X               if (strncmp(*trem,"REMOTE=",7) == 0)
  573. X                 break;
  574. X             for (tproto = envp;*tproto;tproto++)
  575. X               if (strncmp(*tproto,"PROTO=",6) == 0)
  576. X                 break;
  577. X             if (!(*trem && *tproto))
  578. X              {
  579. X               envbak = envp;
  580. X               if ((environ = (char **) malloc((trem - envp + 3) * sizeof(char*)))
  581. X           == NULL)
  582. X                {
  583. X                 perrn2("%s","attachport: fatal: cannot allocate environment");
  584. X                 exit(1);
  585. X                }
  586. X               for (temp = envbak;*temp;temp++)
  587. X                 environ[temp - envbak] = *temp; /* not worth a bcopy */
  588. X               trem = environ + ((*trem ? trem : temp++) - envbak);
  589. X               tproto = environ + ((*tproto ? tproto : temp++) - envbak);
  590. X               environ[temp - envbak] = NULL;
  591. X              }
  592. X             *trem = srem;
  593. X             *tproto = "PROTO=TCP";
  594. X             /* XXXXXX: Should we do confirming sanity checks here? */
  595. X            }
  596. X           (void) close(0); (void) dup(t);
  597. X           (void) close(1); (void) dup(t);
  598. X           (void) close(2); (void) dup(t);
  599. X       for (t = getdtablesize();t > 2;t--)
  600. X             (void) close(t);
  601. X    
  602. X           (void) signal(SIGINT,flagsigintign ? SIG_IGN : SIG_DFL);
  603. X           (void) signal(SIGQUIT,flagsigquitign ? SIG_IGN : SIG_DFL);
  604. X           (void) signal(SIGTSTP,flagsigtstpign ? SIG_IGN : SIG_DFL);
  605. X           (void) signal(SIGHUP,flagsighupign ? SIG_IGN : SIG_DFL);
  606. X           (void) signal(SIGXCPU,flagsigxcpuign ? SIG_IGN : SIG_DFL);
  607. X           (void) signal(SIGXFSZ,flagsigxfszign ? SIG_IGN : SIG_DFL);
  608. X           (void) signal(SIGVTALRM,flagsigvtalrmign ? SIG_IGN : SIG_DFL);
  609. X           (void) signal(SIGPROF,flagsigprofign ? SIG_IGN : SIG_DFL);
  610. X           (void) signal(SIGCHLD,flagsigchldign ? SIG_IGN : SIG_DFL);
  611. X           (void) signal(SIGALRM,flagsigalrmign ? SIG_IGN : SIG_DFL);
  612. X           (void) signal(SIGTERM,flagsigtermign ? SIG_IGN : SIG_DFL);
  613. X
  614. X           if (setreuid(uid,uid))
  615. X            {
  616. X             perrn2("%s","attachport: fatal: cannot setreuid");
  617. X             (void) setreuid(uid,uid); exit(1);
  618. X            }
  619. X
  620. X           /* Yes, Virginia, this is portable. Read execvp(3). */
  621. X           /* Annoying that there isn't a better interface, though. */
  622. X           (void) execvp(*program,program); /* must use environ! */
  623. X       /* option to yell to remote end about failure? hmmm */
  624. X           exit(1);
  625. X          }
  626. X         else if (f == -1)
  627. X          {
  628. X           /* option to yell to remote end before closing? perhaps */
  629. X           (void) close(t); /* sigh */
  630. X           if (setreuid(uid,euid))
  631. X            {
  632. X             perrn2("%s","attachport: warning: cannot setreuid");
  633. X         (void) setreuid(uid,euid);
  634. X            }
  635. X          }
  636. X         else
  637. X          {
  638. X           if (setreuid(uid,euid))
  639. X            {
  640. X             perrn2("%s","attachport: warning: cannot setreuid");
  641. X         (void) setreuid(uid,euid);
  642. X            }
  643. X       numkids++;
  644. X           (void) close(t);
  645. X          }
  646. X       (void) lseek(lockfd,(off_t) 0,0);
  647. X       (void) write(lockfd,lockbuf,lockbuflen);
  648. X       (void) flock(lockfd,LOCK_UN);
  649. X      }
  650. X    }
  651. X /*NOTREACHED*/
  652. X}
  653. END_OF_FILE
  654. if test 20921 -ne `wc -c <'attachport.c'`; then
  655.     echo shar: \"'attachport.c'\" unpacked with wrong size!
  656. fi
  657. # end of 'attachport.c'
  658. fi
  659. if test -f 'authtcp.c' -a "${1}" != "-c" ; then 
  660.   echo shar: Will not clobber existing file \"'authtcp.c'\"
  661. else
  662. echo shar: Extracting \"'authtcp.c'\" \(19108 characters\)
  663. sed "s/^X//" >'authtcp.c' <<'END_OF_FILE'
  664. X/*
  665. Xauthtcp.c: Create a locally authenticated TCP connection.
  666. X*/
  667. X
  668. X/* WARNING! WARNING! WARNING! */
  669. X/* For the authentication to work, authtcp must run setuid auth! */
  670. X/* All setuid programs are dangerous! Check them carefully! */
  671. X
  672. Xstatic char authtcpauthor[] =
  673. X"authtcp was written by Daniel J. Bernstein.\n\
  674. XInternet address: brnstnd@acf10.nyu.edu.\n";
  675. X
  676. Xstatic char authtcpversion[] = 
  677. X"authtcp version 2.1, April 18, 1990.\n\
  678. XCopyright (c) 1990, Daniel J. Bernstein.\n\
  679. XAll rights reserved.\n";
  680. X
  681. Xstatic char authtcpcopyright[] =
  682. X"authtcp version 2.1, April 18, 1990.\n\
  683. XCopyright (c) 1990, Daniel J. Bernstein.\n\
  684. XAll rights reserved.\n\
  685. X\n\
  686. XUntil January 1, 1995, you are granted the following rights: A. To make\n\
  687. Xcopies of this work in original form, so long as (1) the copies are exact\n\
  688. Xand complete; (2) the copies include the copyright notice, this paragraph,\n\
  689. Xand the disclaimer of warranty in their entirety. B. To distribute this\n\
  690. Xwork, or copies made under the provisions above, so long as (1) this is\n\
  691. Xthe original work and not a derivative form; (2) you do not charge a fee\n\
  692. Xfor copying or for distribution; (3) you ensure that the distributed form\n\
  693. Xincludes the copyright notice, this paragraph, and the disclaimer of\n\
  694. Xwarranty in their entirety. These rights are temporary and revocable upon\n\
  695. Xwritten, oral, or other notice by Daniel J. Bernstein. These rights are\n\
  696. Xautomatically revoked on January 1, 1995. This copyright notice shall be\n\
  697. Xgoverned by the laws of the state of New York.\n\
  698. X\n\
  699. XIf you have questions about authtcp or about this copyright notice,\n\
  700. Xor if you would like additional rights beyond those granted above,\n\
  701. Xplease feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  702. Xon the Internet.\n";
  703. X
  704. Xstatic char authtcpwarranty[] =
  705. X"To the extent permitted by applicable law, Daniel J. Bernstein disclaims\n\
  706. Xall warranties, explicit or implied, including but not limited to the\n\
  707. Ximplied warranties of merchantability and fitness for a particular purpose.\n\
  708. XDaniel J. Bernstein is not and shall not be liable for any damages,\n\
  709. Xincidental or consequential, arising from the use of this program, even\n\
  710. Xif you inform him of the possibility of such damages. This disclaimer\n\
  711. Xshall be governed by the laws of the state of New York.\n\
  712. X\n\
  713. XIn other words, use this program at your own risk.\n\
  714. X\n\
  715. XIf you have questions about authtcp or about this disclaimer of warranty,\n\
  716. Xplease feel free to contact the author at brnstnd@acf10.nyu.edu\n\
  717. Xon the Internet.\n";
  718. X
  719. Xstatic char authtcpusage[] =
  720. X"Usage: authtcp [ -dn ] [ -pport ] [ -xXvACHUVW ] inetaddr tcpport program \n\
  721. XHelp:  authtcp -H\n";
  722. X
  723. Xstatic char authtcphelp[] =
  724. X"authtcp creates a locally authenticated TCP connection to an Internet host.\n\
  725. X\n\
  726. Xauthtcp -A: print authorship notice\n\
  727. Xauthtcp -C: print copyright notice\n\
  728. Xauthtcp -H: print this notice\n\
  729. Xauthtcp -U: print short usage summary\n\
  730. Xauthtcp -V: print version number\n\
  731. Xauthtcp -W: print disclaimer of warranty\n\
  732. X\n\
  733. Xauthtcp [ -dn ] [ -pport ] [ -vxXrR ] inetaddr tcpport program:\n\
  734. X        connect to tcpport at inetaddr and run program\n\
  735. X  -dn: pass the connection to the program in file descriptor n (default 6)\n\
  736. X  -pport: attempt to use a particular local port\n\
  737. X  -v: verbose: proclaim success; report unusual program termination\n\
  738. X  -x: authenticate by telling authd(8) about the connection (default)\n\
  739. X  -X: do not locally authenticate\n\
  740. X  -r: attempt to authenticate the remote side as well (default), placing\n\
  741. X      user@host and TCP into environment variables REMOTE and PROTO\n\
  742. X  -R: do not remotely authenticate\n\
  743. X\n\
  744. XIf you have questions about or suggestions for authtcp, please feel free\n\
  745. Xto contact the author, Daniel J. Bernstein, at brnstnd@acf10.nyu.edu\n\
  746. Xon the Internet.\n";
  747. X
  748. X#include <stdio.h>
  749. X#include <sys/types.h>
  750. X#include <sys/socket.h>
  751. X#include <netinet/in.h>
  752. X#include <arpa/inet.h>
  753. X#include <netdb.h>
  754. X#include <errno.h>
  755. Xextern int errno;
  756. Xextern char *malloc(); /* many systems don't have malloc.h */
  757. X#include <pwd.h>
  758. X#include <sys/file.h>
  759. X#ifdef BSD
  760. X#include <limits.h>
  761. X#endif
  762. X#include <sys/wait.h>
  763. X#include <sys/time.h>
  764. X#include <sys/resource.h>
  765. X#include <signal.h>
  766. X#include <ctype.h>
  767. Xextern int getopt();
  768. Xextern char *optarg; /* these should be in getopt.h! */
  769. Xextern int optind;
  770. X#include "authuser.h"
  771. X#include "djberr.h"
  772. X#include "djbatoi.h"
  773. X
  774. X#ifndef AUTHDIR
  775. X#define AUTHDIR "/usr/etc/auth"
  776. X#endif
  777. X
  778. X#ifndef MAXHOSTNAMELEN
  779. X#define MAXHOSTNAMELEN 128 /* stupid Suns don't define this in sys/param.h */
  780. X#endif
  781. X
  782. Xint flagcont = 0;
  783. X
  784. Xsigcont()
  785. X{
  786. X flagcont = 1;
  787. X}
  788. X
  789. Xint flagauth = 1;
  790. Xint flagremote = 1;
  791. Xint filedesc = 6;
  792. Xunsigned short localport = 0;
  793. X
  794. Xchar *strinetaddr = NULL;
  795. Xchar *strtcpport = NULL;
  796. Xchar **program = NULL;
  797. X
  798. Xmain(argc,argv,envp)
  799. Xint argc;
  800. Xchar *argv[];
  801. Xchar *envp[];
  802. X{
  803. X extern char **environ;
  804. X int opt;
  805. X struct sockaddr_in sa;
  806. X unsigned long in;
  807. X unsigned short remoteport;
  808. X int s;
  809. X int t;
  810. X int uid;
  811. X int euid;
  812. X int dummy;
  813. X char authfn[sizeof(AUTHDIR) + 30];
  814. X int authfd;
  815. X char lockfn[sizeof(AUTHDIR) + 30];
  816. X int lockfd;
  817. X char lockbuf[32]; /* 5 pid, 1 :, 10 I, 1 ., 5 R, 1 \n, 8 U, 1\0 */
  818. X struct passwd *pw;
  819. X char strfd[20];
  820. X int flagverbose = 0;
  821. X struct hostent *he;
  822. X struct servent *se;
  823. X union wait status;
  824. X int f;
  825. X struct in_addr inet; /* dummy for inet_ntoa() */
  826. X int flagsigintign;
  827. X int flagsigquitign;
  828. X int flagsigtstpign;
  829. X int flagsighupign;
  830. X int flagsigalrmign;
  831. X int flagsigxcpuign;
  832. X int flagsigxfszign;
  833. X int flagsigvtalrmign;
  834. X int flagsigprofign;
  835. X
  836. X /* ALERT! ALERT! ALERT! We're probably running setuid auth! */
  837. X /* Note that accounting is by real uid, not effective uid. */
  838. X /* The system should be careful about setuid core dumps 'n' such. */
  839. X
  840. X uid = getuid();
  841. X euid = geteuid();
  842. X
  843. X /* The following are necessary to be absolutely sure of removing the
  844. X    authentication entry. It's a flaw of the signal handling system that
  845. X    every new extension could turn a secure program like this into an
  846. X    (ever so slightly) insecure one. */
  847. X flagsigintign = (signal(SIGINT,SIG_IGN) == SIG_IGN);
  848. X flagsigquitign = (signal(SIGQUIT,SIG_IGN) == SIG_IGN);
  849. X flagsigtstpign = (signal(SIGTSTP,SIG_IGN) == SIG_IGN);
  850. X flagsighupign = (signal(SIGHUP,SIG_IGN) == SIG_IGN);
  851. X flagsigalrmign = (signal(SIGALRM,SIG_IGN) == SIG_IGN);
  852. X flagsigxcpuign = (signal(SIGXCPU,SIG_IGN) == SIG_IGN);
  853. X flagsigxfszign = (signal(SIGXFSZ,SIG_IGN) == SIG_IGN);
  854. X flagsigvtalrmign = (signal(SIGVTALRM,SIG_IGN) == SIG_IGN);
  855. X flagsigprofign = (signal(SIGPROF,SIG_IGN) == SIG_IGN);
  856. X /* At least we can depend on SIG_IGN and SIG_DFL being the only
  857. X    possible handlers passed through an exec. Programmers should note
  858. X    the above trick to avoid having to worry about the signal() type. */
  859. X
  860. X while ((opt = getopt(argc,argv,"rRxXd:p:vACHUVW")) != EOF)
  861. X   switch(opt)
  862. X    {
  863. X     case 'r': flagremote = 1; break;
  864. X     case 'R': flagremote = 0; break;
  865. X     case 'x': flagauth = 1; break;
  866. X     case 'X': flagauth = 0; break;
  867. X     case 'd': filedesc = atoi(optarg); break;
  868. X     case 'p': localport = atoi(optarg); break;
  869. X     case 'v': flagverbose = 1; break;
  870. X     case 'A': (void) err(authtcpauthor); (void) setreuid(uid,uid); exit(1);
  871. X     case 'C': (void) err(authtcpcopyright); (void) setreuid(uid,uid); exit(1);
  872. X     case 'H': (void) err(authtcphelp); (void) setreuid(uid,uid); exit(1);
  873. X     case 'U': (void) err(authtcpusage); (void) setreuid(uid,uid); exit(1);
  874. X     case 'V': (void) err(authtcpversion); (void) setreuid(uid,uid); exit(1);
  875. X     case 'W': (void) err(authtcpwarranty); (void) setreuid(uid,uid); exit(1);
  876. X     case '?': (void) err(authtcpusage); (void) setreuid(uid,uid); exit(1);
  877. X    }
  878. X argv += optind, argc -= optind;
  879. X while (*argv)
  880. X  {
  881. X   if (strinetaddr == NULL)
  882. X     strinetaddr = *argv;
  883. X   else if (strtcpport == NULL)
  884. X     strtcpport = *argv;
  885. X   else
  886. X    {
  887. X     program = argv;
  888. X     break;
  889. X    }
  890. X   argv++;
  891. X  }
  892. X
  893. X if ((program == NULL) || (*program == NULL))
  894. X  {
  895. X   err(authtcpusage); (void) setreuid(uid,uid); exit(1);
  896. X   /* what else can you say? */
  897. X  }
  898. X t = strlen(strinetaddr) - 1;
  899. X if (isascii(strinetaddr[t]) && isdigit(strinetaddr[t]))
  900. X   in = inet_addr(strinetaddr);
  901. X else
  902. X   if ((he = gethostbyname(strinetaddr)) == NULL)
  903. X     in = (unsigned long) -1;
  904. X   else
  905. X     in = *((unsigned long *) (he->h_addr));
  906. X
  907. X if (in == (unsigned long) -1)
  908. X  {
  909. X   errn2("authtcp: fatal: do not understand inetaddr %s",strinetaddr);
  910. X   (void) setreuid(uid,uid);
  911. X   exit(1);
  912. X  }
  913. X
  914. X t = strlen(strtcpport) - 1;
  915. X if (isascii(strtcpport[t]) && isdigit(strtcpport[t]))
  916. X   remoteport = atoi(strtcpport); /* so who cares if it's zero? */
  917. X else
  918. X   if ((se = getservbyname(strtcpport,"tcp")) == NULL)
  919. X     remoteport = 0;
  920. X   else
  921. X     remoteport = ntohs(se->s_port); /* inconsistency alert! */
  922. X                     /* se->s_port is int! */
  923. X
  924. X /* We will depend on the type of localport and remoteport, namely */
  925. X /* unsigned short, to keep them between 0 and 65535. */
  926. X
  927. X /* The parent program must remain active and setuid auth, to wait for */
  928. X /* the child to finish and to remove its authentication entry. But the */
  929. X /* TCP connection must be made as the user---don't want fake rlogins! */
  930. X
  931. X /* We now switch to the real user ID. */
  932. X
  933. X if (setreuid(euid,uid))
  934. X  {
  935. X   perrn2("%s","authtcp: fatal: cannot setreuid");
  936. X   (void) setreuid(uid,uid);
  937. X   exit(1);
  938. X  }
  939. X
  940. X if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) /* no security problem */
  941. X  {
  942. X   perrn2("%s","authtcp: fatal: cannot create socket");
  943. X   (void) setreuid(uid,uid);
  944. X   exit(1);
  945. X  }
  946. X
  947. X /* The bind() below used to be if (localport) only. However, connect() */
  948. X /* can take arbitrarily long, there's no solution like select-accept, */
  949. X /* and authd should not have to wait to get its information. So we have */
  950. X /* to find our local port now. This is documented to work in PS1:8-31. */
  951. X
  952. X sa.sin_family = AF_INET;
  953. X sa.sin_port = htons(localport); /* ever seen a client do this before? */
  954. X sa.sin_addr.s_addr = INADDR_ANY; /* or this? */
  955. X if (bind(s,&sa,sizeof(sa)) == -1)
  956. X   if (localport)
  957. X    {
  958. X     perrn2("authtcp: fatal: cannot bind local port %u",
  959. X            (unsigned int) localport);
  960. X     (void) setreuid(uid,uid);
  961. X     exit(1);
  962. X    }
  963. X   else
  964. X    {
  965. X     perrn2("%s","authtcp: fatal: cannot bind local port");
  966. X     (void) setreuid(uid,uid);
  967. X     exit(1);
  968. X    }
  969. X
  970. X /* We now switch back to auth... */
  971. X if (setreuid(uid,euid))
  972. X  {
  973. X   perrn2("%s","authtcp: fatal: cannot setreuid");
  974. X   (void) setreuid(uid,uid);
  975. X   exit(1);
  976. X  }
  977. X
  978. X if (flagauth)
  979. X  {
  980. X   dummy = sizeof(sa);
  981. X   if ((pw = getpwuid(uid)) == NULL)
  982. X    {
  983. X     errn("authtcp: fatal: cannot authenticate: who are you?");
  984. X     (void) setreuid(uid,uid);
  985. X     exit(1);
  986. X    }
  987. X   if (getsockname(s,&sa,&dummy) == -1)
  988. X    {
  989. X     perrn2("%s","authtcp: fatal: cannot get socket name");
  990. X     (void) setreuid(uid,uid);
  991. X     exit(1);
  992. X    }
  993. X   (void) sprintf(authfn,"%s/tcp/%D.%u.%u",AUTHDIR,in,
  994. X          (unsigned int) ntohs(sa.sin_port),(unsigned int) remoteport);
  995. X   (void) sprintf(lockfn,"%s/tcp/lock.%u",AUTHDIR,
  996. X          (unsigned int) ntohs(sa.sin_port));
  997. X   if (((lockfd = open(lockfn,O_WRONLY | O_CREAT | O_EXCL,0600)) == -1)
  998. X     &&(((lockfd = open(lockfn,O_RDONLY)) == -1)
  999. X    ||(flock(lockfd,LOCK_EX) == -1)
  1000. X        ||(read(lockfd,lockbuf,31) <= 0)
  1001. X    ||((lockbuf[0] != '!')
  1002. X          &&((atoi(lockbuf) <= 0)
  1003. X             ||(kill(atoi(lockbuf),0) == 0))) /* okay, screw the last process */
  1004. X    ||(close(lockfd) == -1) /* impossible */
  1005. X        ||((lockfd = open(lockfn,O_WRONLY | O_CREAT | O_TRUNC,0600)) == -1)))
  1006. X    { /* yikes, that was incomprehensible */
  1007. X     errn2("authtcp: fatal: local port %u locked",
  1008. X       (unsigned int) ntohs(sa.sin_port));
  1009. X     (void) setreuid(uid,uid);
  1010. X     exit(1);
  1011. X    }
  1012. X   (void) flock(lockfd,LOCK_EX);
  1013. X   (void) sprintf(lockbuf,"%d:%D.%u\n%s",getpid(),in,(unsigned int) remoteport,
  1014. X              pw->pw_name);
  1015. X   (void) write(lockfd,lockbuf,strlen(lockbuf));
  1016. X   (void) flock(lockfd,LOCK_UN);
  1017. X  }
  1018. X /* It isn't a disaster if the user kills us now; it's just a possible */
  1019. X /* denial of service for later auths on this port. The amount of effort */
  1020. X /* necessary to guarantee that denial is huge. */
  1021. X
  1022. X /* We now switch back to real... */
  1023. X if (setreuid(euid,uid))
  1024. X  {
  1025. X   perrn2("%s","authtcp: fatal: cannot setreuid");
  1026. X   (void) setreuid(uid,euid);
  1027. X   if (flagauth)
  1028. X     (void) unlink(lockfn);
  1029. X   (void) setreuid(uid,uid);
  1030. X   exit(1);
  1031. X  }
  1032. X
  1033. X sa.sin_family = AF_INET;
  1034. X sa.sin_port = htons(remoteport);
  1035. X sa.sin_addr.s_addr = in;
  1036. X
  1037. X if (connect(s,&sa,sizeof(sa)) == -1)
  1038. X  {
  1039. X   perrn2("authtcp: fatal: cannot connect to %s",strinetaddr);
  1040. X   (void) setreuid(uid,euid);
  1041. X   if (flagauth)
  1042. X     (void) unlink(lockfn);
  1043. X   (void) setreuid(uid,uid);
  1044. X   exit(1);
  1045. X  }
  1046. X
  1047. X if (flagverbose)
  1048. X  {
  1049. X   inet.s_addr = in;
  1050. X   fprintf(stderr,"authtcp: connected to %s port %u\n",
  1051. X       inet_ntoa(inet),(unsigned int) remoteport);
  1052. X  }
  1053. X
  1054. X /* We now have the uids switched, the connection open in socket s. */
  1055. X
  1056. X /* We're about to write the authentication entry. We must remove it */
  1057. X /* before coming back to the real uid and/or exiting. On the other */
  1058. X /* hand, we must fork as the real uid: one system stupidity is that */
  1059. X /* fork() uses the effective uid for MAXUPRC checks. Hence we fork */
  1060. X /* as the real (i.e. switched) uid, before authentication. In fact, */
  1061. X /* we delay authentication until it's convenient in the parent; the */
  1062. X /* child program could run before the authentication file exists. */
  1063. X /* This is not a race condition, for reasons explained in dir.doc. */
  1064. X
  1065. X if ((f = fork()) == 0) /* child */
  1066. X  {
  1067. X   if (setreuid(uid,uid))
  1068. X    {
  1069. X     perrn2("%s","authtcp: fatal: cannot setreuid");
  1070. X     exit(1);
  1071. X    }
  1072. X   if (filedesc)
  1073. X    {
  1074. X     if (dup2(s,filedesc) == -1)
  1075. X      {
  1076. X       perrn2("%s","authtcp: fatal: cannot use file descriptor");
  1077. X       exit(1);
  1078. X      }
  1079. X    }
  1080. X   else
  1081. X    {
  1082. X     (void) sprintf(strfd,"%d",s);
  1083. X     while (*(++argv))
  1084. X       if ((**argv == '=') && (*(*argv + 1) == '\0'))
  1085. X    {
  1086. X     *argv = strfd;
  1087. X     break;
  1088. X    }
  1089. X     /* don't need to complain about failure here */
  1090. X    }
  1091. X
  1092. X   if (flagremote)
  1093. X    {
  1094. X     unsigned long in; /* keep confirming variables separate */
  1095. X     unsigned short local;
  1096. X     unsigned short remote;
  1097. X     char *ruser;
  1098. X     char *srem;
  1099. X     char **t;
  1100. X     char **trem;
  1101. X     char **tproto;
  1102. X     char **envbak;
  1103. X
  1104. X     if (auth_fd(s,&in,&local,&remote) == -1)
  1105. X      {
  1106. X       perrn2("%s","authtcp: fatal: cannot confirm connection");
  1107. X       exit(1);
  1108. X      }
  1109. X     if ((ruser = auth_tcpuser(in,local,remote)) == NULL)
  1110. X       ruser = ""; /* bummer */
  1111. X     if ((srem = malloc(strlen(ruser) + 30)) == NULL)
  1112. X      {
  1113. X       perrn2("%s","authtcp: fatal: cannot allocate environment");
  1114. X       exit(1);
  1115. X      }
  1116. X     inet.s_addr = in;
  1117. X     sprintf(srem,"REMOTE=%s@%s",ruser,inet_ntoa(inet));
  1118. X     for (trem = envp;*trem;trem++)
  1119. X       if (strncmp(*trem,"REMOTE=",7) == 0)
  1120. X         break;
  1121. X     for (tproto = envp;*tproto;tproto++)
  1122. X       if (strncmp(*tproto,"PROTO=",6) == 0)
  1123. X         break;
  1124. X     if (!(*trem && *tproto))
  1125. X      {
  1126. X       envbak = envp;
  1127. X       if ((environ = (char **) malloc((trem - envp + 3) * sizeof(char *)))
  1128. X       == NULL)
  1129. X        {
  1130. X         perrn2("%s","authtcp: fatal: cannot allocate environment");
  1131. X         exit(1);
  1132. X        }
  1133. X       for (t = envbak;*t;t++)
  1134. X         environ[t - envbak] = *t; /* not worth a bcopy */
  1135. X       trem = environ + ((*trem ? trem : t++) - envbak);
  1136. X       tproto = environ + ((*tproto ? tproto : t++) - envbak);
  1137. X       environ[t - envbak] = NULL;
  1138. X      }
  1139. X     *trem = srem;
  1140. X     *tproto = "PROTO=TCP";
  1141. X     /* XXXXXX: Should we do confirming sanity checks here? */
  1142. X    }
  1143. X
  1144. X   (void) signal(SIGINT,flagsigintign ? SIG_IGN : SIG_DFL);
  1145. X   (void) signal(SIGQUIT,flagsigquitign ? SIG_IGN : SIG_DFL);
  1146. X   (void) signal(SIGTSTP,flagsigtstpign ? SIG_IGN : SIG_DFL);
  1147. X   (void) signal(SIGHUP,flagsighupign ? SIG_IGN : SIG_DFL);
  1148. X   (void) signal(SIGALRM,flagsigalrmign ? SIG_IGN : SIG_DFL);
  1149. X   (void) signal(SIGXCPU,flagsigxcpuign ? SIG_IGN : SIG_DFL);
  1150. X   (void) signal(SIGXFSZ,flagsigxfszign ? SIG_IGN : SIG_DFL);
  1151. X   (void) signal(SIGVTALRM,flagsigvtalrmign ? SIG_IGN : SIG_DFL);
  1152. X   (void) signal(SIGPROF,flagsigprofign ? SIG_IGN : SIG_DFL);
  1153. X
  1154. X   /* Yes, Virginia, this is portable. Read execvp(3). */
  1155. X   /* Annoying that there isn't a better interface, though. */
  1156. X   (void) execvp(*program,program); /* must use environ! */
  1157. X   perrn2("authtcp: fatal: cannot execute %s",*program);
  1158. X   exit(1);
  1159. X  }
  1160. X /* no need to test for failing fork */
  1161. X
  1162. X if (setreuid(uid,euid))
  1163. X  {
  1164. X   perrn2("%s","authtcp: fatal: cannot setreuid");
  1165. X   (void) setreuid(uid,euid);
  1166. X   if (flagauth)
  1167. X     (void) unlink(lockfn);
  1168. X   (void) setreuid(uid,uid);
  1169. X   exit(1);
  1170. X  }
  1171. X /* Now we're back to setuid auth in the parent, as we will remain. */
  1172. X
  1173. X if (flagauth)
  1174. X  {
  1175. X   /* authfn and pw are put together up above */
  1176. X   if ((authfd = open(authfn,O_WRONLY | O_CREAT | O_EXCL,0600)) == -1)
  1177. X    {
  1178. X     perrn2("%s","authtcp: fatal: cannot authenticate");
  1179. X     (void) setreuid(uid,euid);
  1180. X     if (flagauth)
  1181. X       (void) unlink(lockfn);
  1182. X     (void) setreuid(uid,uid);
  1183. X     exit(1);
  1184. X    }
  1185. X   (void) write(authfd,pw->pw_name,strlen(pw->pw_name));
  1186. X   (void) close(authfd); /* if it fails, tough luck. */
  1187. X  }
  1188. X
  1189. X (void) signal(SIGCONT,sigcont);
  1190. X
  1191. X /* Unless the user is auth we won't receive any signals. So the */
  1192. X /* following handlers are mainly a convenience on machines where */
  1193. X /* authtcp is not installed by the sysadmin. */
  1194. X (void) signal(SIGTERM,SIG_IGN); /* kill child, not us! */
  1195. X (void) signal(SIGTTOU,SIG_DFL); /* for stopping */
  1196. X (void) signal(SIGTTIN,SIG_DFL); /* for stopping */
  1197. X
  1198. X /* We're going to leave the socket open, to completely close a possible */
  1199. X /* security hole. The application must not depend upon the connection */
  1200. X /* disappearing when it's closed. */
  1201. X
  1202. X for (t = getdtablesize();t >= 0;t--)
  1203. X   if ((s != t) && (t != 2)) /* have to leave stderr open! */
  1204. X     (void) close(t); /* might as well do a bit of dissociation */
  1205. X
  1206. X while (wait3(&status,WUNTRACED,(struct rusage *) NULL) >= 0)
  1207. X  {
  1208. X   if (status.w_stopval == WSTOPPED) /* if child stops, we stop */
  1209. X    {
  1210. X     flagcont = 0;
  1211. X     (void) signal(SIGTSTP,SIG_DFL); /* for stopping */
  1212. X     switch(status.w_stopsig)
  1213. X      { /* this just looks good */
  1214. X       case SIGSTOP: (void) kill(getpid(),SIGSTOP); break;
  1215. X       case SIGTSTP: (void) kill(getpid(),SIGTSTP); break;
  1216. X       case SIGTTOU: (void) kill(getpid(),SIGTTOU); break;
  1217. X       case SIGTTIN: (void) kill(getpid(),SIGTTIN); break;
  1218. X       default: (void) kill(getpid(),SIGSTOP); break;
  1219. X      }
  1220. X     while (flagcont == 0)
  1221. X       ; /* rack up CPU time waiting for the CONT---is there a better way? */
  1222. X     (void) signal(SIGTSTP,SIG_IGN);
  1223. X     (void) kill(f,SIGCONT); /* when we start, child starts */
  1224. X     continue;
  1225. X    }
  1226. X   if (flagverbose)
  1227. X     if (WIFSIGNALED(status))
  1228. X       if (status.w_coredump)
  1229. X    {
  1230. X     errn2("authtcp: fatal: killed by signal %d (core dumped)",
  1231. X               status.w_termsig);
  1232. X    }
  1233. X       else
  1234. X    {
  1235. X     errn2("authtcp: fatal: killed by signal %d",status.w_termsig);
  1236. X    }
  1237. X   break;
  1238. X  }
  1239. X
  1240. X if (flagauth)
  1241. X  {
  1242. X   if (unlink(authfn) == -1) /* had better succeed! */
  1243. X    {
  1244. X     perrn2("authtcp: fatal: cannot unlink authentication entry %s",authfn);
  1245. X     exit(1);
  1246. X    }
  1247. X   (void) unlink(lockfn);
  1248. X  }
  1249. X
  1250. X exit(WIFEXITED(status) ? ((int) status.w_retcode) : 1);
  1251. X}
  1252. END_OF_FILE
  1253. if test 19108 -ne `wc -c <'authtcp.c'`; then
  1254.     echo shar: \"'authtcp.c'\" unpacked with wrong size!
  1255. fi
  1256. # end of 'authtcp.c'
  1257. fi
  1258. if test -f 'rfc931' -a "${1}" != "-c" ; then 
  1259.   echo shar: Will not clobber existing file \"'rfc931'\"
  1260. else
  1261. echo shar: Extracting \"'rfc931'\" \(9196 characters\)
  1262. sed "s/^X//" >'rfc931' <<'END_OF_FILE'
  1263. X
  1264. X
  1265. X
  1266. X
  1267. X
  1268. X---------
  1269. X
  1270. X
  1271. X< INC-PROJECT, AUTH-RFC-VER-2.NLS.5, >, 7-Jan-85 17:18-PST JBP
  1272. X;;;;
  1273. X
  1274. X
  1275. X
  1276. X
  1277. X
  1278. X
  1279. X
  1280. X
  1281. X
  1282. X
  1283. X
  1284. X
  1285. X
  1286. X
  1287. X
  1288. X
  1289. X
  1290. X
  1291. X
  1292. X
  1293. X
  1294. X
  1295. X
  1296. X
  1297. X
  1298. X
  1299. X
  1300. X
  1301. X
  1302. X
  1303. X
  1304. X
  1305. X
  1306. X
  1307. X
  1308. X
  1309. X
  1310. X
  1311. X
  1312. X
  1313. X
  1314. X
  1315. X
  1316. X
  1317. X
  1318. X
  1319. X
  1320. X
  1321. X
  1322. X
  1323. X
  1324. XStJohns                                                         [Page 0]
  1325. X
  1326. X
  1327. XNetwork Working Group                                       Mike StJohns
  1328. XRequest for Comments: 931                                           TPSC
  1329. XSupersedes: RFC 912                                         January 1985
  1330. X
  1331. X                         Authentication Server
  1332. X
  1333. X
  1334. XSTATUS OF THIS MEMO
  1335. X
  1336. X   This RFC suggests a proposed protocol for the ARPA-Internet
  1337. X   community, and requests discussion and suggestions for improvements.
  1338. X   This is the second draft of this proposal (superseding RFC 912) and
  1339. X   incorporates a more formal description of the syntax for the request
  1340. X   and response dialog, as well as a change to specify the type of user
  1341. X   identification returned.  Distribution of this memo is unlimited.
  1342. X
  1343. XINTRODUCTION
  1344. X
  1345. X   The Authentication Server Protocol provides a means to determine the
  1346. X   identity of a user of a particular TCP connection.  Given a TCP port
  1347. X   number pair, it returns a character string which identifies the owner
  1348. X   of that connection on the server's system.  Suggested uses include
  1349. X   automatic identification and verification of a user during an FTP
  1350. X   session, additional verification of a TAC dial up user, and access
  1351. X   verification for a generalized network file server.
  1352. X
  1353. XOVERVIEW
  1354. X
  1355. X   This is a connection based application on TCP.  A server listens for
  1356. X   TCP connections on TCP port 113 (decimal).  Once a connection is
  1357. X   established, the server reads one line of data which specifies the
  1358. X   connection of interest.  If it exists, the system dependent user
  1359. X   identifier of the connection of interest is sent out the connection.
  1360. X   The service closes the connection after sending the user identifier.
  1361. X
  1362. XRESTRICTIONS
  1363. X
  1364. X   Queries are permitted only for fully specified connections. The
  1365. X   local/foreign host pair used to fully specify the connection are
  1366. X   taken from the query connection.  This means a user on Host A may
  1367. X   only query the server on Host B about connections between A and B.
  1368. X
  1369. X
  1370. X
  1371. X
  1372. X
  1373. X
  1374. X
  1375. X
  1376. X
  1377. X
  1378. X
  1379. X
  1380. XStJohns                                                         [Page 1]
  1381. X
  1382. X
  1383. XRFC 931                                                     January 1985
  1384. XAuthentication Server
  1385. X
  1386. X
  1387. XQUERY/RESPONSE FORMAT
  1388. X
  1389. X   The server accepts simple text query requests of the form
  1390. X
  1391. X      <local-port>, <foreign-port>
  1392. X
  1393. X   where <local-port> is the TCP port (decimal) on the target (server)
  1394. X   system, and <foreign-port> is the TCP port (decimal) on the source
  1395. X   (user) system.
  1396. X
  1397. X      For example:
  1398. X
  1399. X         23, 6191
  1400. X
  1401. X   The response is of the form
  1402. X
  1403. X      <local-port>, <foreign-port> : <response-type> : <additional-info>
  1404. X
  1405. X   where <local-port>,<foreign-port> are the same pair as the query,
  1406. X   <response-type> is a keyword identifying the type of response, and
  1407. X   <additional info> is context dependent.
  1408. X
  1409. X      For example:
  1410. X
  1411. X         23, 6191 : USERID : MULTICS : StJohns.DODCSC.a
  1412. X         23, 6193 : USERID : TAC : MCSJ-MITMUL
  1413. X         23, 6195 : ERROR : NO-USER
  1414. X
  1415. XRESPONSE TYPES
  1416. X
  1417. X   A response can be one of two types:
  1418. X
  1419. X   USERID
  1420. X
  1421. X      In this case, <additional-info> is a string consisting of an
  1422. X      operating system name, followed by a ":", followed by user
  1423. X      identification string in a format peculiar to the operating system
  1424. X      indicated.  Permitted operating system names are specified in
  1425. X      RFC-923, "Assigned Numbers" or its successors.  The only other
  1426. X      names permitted are "TAC" to specify a BBN Terminal Access
  1427. X      Controller, and "OTHER" to specify any other operating system not
  1428. X      yet registered with the NIC.
  1429. X
  1430. X
  1431. X
  1432. X
  1433. X
  1434. X
  1435. X
  1436. XStJohns                                                         [Page 2]
  1437. X
  1438. X
  1439. XRFC 931                                                     January 1985
  1440. XAuthentication Server
  1441. X
  1442. X
  1443. X   ERROR
  1444. X
  1445. X      For some reason the owner of <TCP-port> could not be determined,
  1446. X      <additional-info> tells why.  The following are suggested values
  1447. X      of <additional-info> and their meanings.
  1448. X
  1449. X      INVALID-PORT
  1450. X
  1451. X         Either the local or foreign port was improperly specified.
  1452. X
  1453. X      NO-USER
  1454. X
  1455. X         The connection specified by the port pair is not currently in
  1456. X         use.
  1457. X
  1458. X      UNKNOWN-ERROR
  1459. X
  1460. X         Can't determine connection owner; reason unknown.  Other values
  1461. X         may be specified as necessary.
  1462. X
  1463. XCAVEATS
  1464. X
  1465. X   Unfortunately, the trustworthiness of the various host systems that
  1466. X   might implement an authentication server will vary quite a bit.  It
  1467. X   is up to the various applications that will use the server to
  1468. X   determine the amount of trust they will place in the returned
  1469. X   information.  It may be appropriate in some cases restrict the use of
  1470. X   the server to within a locally controlled subnet.
  1471. X
  1472. XAPPLICATIONS
  1473. X
  1474. X   1) Automatic user authentication for FTP
  1475. X
  1476. X      A user-FTP may send a USER command with no argument to the
  1477. X      server-FTP to request automatic authentication.  The server-FTP
  1478. X      will reply with a 230 (user logged in) if it can use the
  1479. X      authentication.  It will reply with a 530 (not logged in) if it
  1480. X      cannot authenticate the user.  It will reply with a 500 or 501
  1481. X      (syntax or parameter problem) if it does not implement automatic
  1482. X      authentication.  Please note that no change is needed to currently
  1483. X      implemented servers to handle the request for authentication; they
  1484. X      will reject it normally as a parameter problem.  This is a
  1485. X      suggested implementation for experimental use only.
  1486. X
  1487. X   2) Verification for privileged network operations.  For example,
  1488. X   having the server start or stop special purpose servers.
  1489. X
  1490. X
  1491. X
  1492. XStJohns                                                         [Page 3]
  1493. X
  1494. X
  1495. XRFC 931                                                     January 1985
  1496. XAuthentication Server
  1497. X
  1498. X
  1499. X   3) Elimination of "double login" for TAC and other TELNET users.
  1500. X
  1501. X      This will be implemented as a TELNET option.
  1502. X
  1503. XFORMAL SYNTAX
  1504. X
  1505. X   <request>     ::= <port-pair> <CR> <LF>
  1506. X
  1507. X   <port-pair>   ::= <integer-number> "," <integer-number>
  1508. X
  1509. X   <reply>       ::= <reply-text> <CR> <LF>
  1510. X
  1511. X   <reply-text>  ::= <error-reply> | <auth-reply>
  1512. X
  1513. X   <error-reply> ::= <port-pair> ":" ERROR ":" <error-type>
  1514. X
  1515. X   <auth-reply>  ::= <port-pair> ":" USERID ":" <opsys> ":" <user-id>
  1516. X
  1517. X   <error-type>  ::= INVALID-PORT | NO-USER | UNKNOWN-ERROR
  1518. X
  1519. X   <opsys>       ::= TAC | OTHER | MULTICS | UNIX ...etc.
  1520. X                     (See "Assigned Numbers")
  1521. X
  1522. X   Notes on Syntax:
  1523. X
  1524. X      1)  White space (blanks and tab characters) between tokens is not
  1525. X      important and may be ignored.
  1526. X
  1527. X      2)  White space, the token separator character (":"), and the port
  1528. X      pair separator character (",") must be quoted if used within a
  1529. X      token.  The quote character is a back-slash, ASCII 92 (decimal)
  1530. X      ("\").  For example, a quoted colon is "\:".  The back-slash must
  1531. X      also be quoted if its needed to represent itself ("\\").
  1532. X
  1533. XNotes on User Identification Format:
  1534. X
  1535. X   The user identifier returned by the server should be the standard one
  1536. X   for the system.  For example, the standard Multics identifier
  1537. X   consists of a PERSONID followed by a ".", followed by a PROJECTID,
  1538. X   followed by a ".", followed by an INSTANCE TAG of one character.  An
  1539. X   instance tag of "a" identifies an interactive user, and instance tag
  1540. X   of "m" identifies an absentee job (batch job) user, and an instance
  1541. X   tag of "z" identifies a daemon (background) user.
  1542. X
  1543. X   Each set of operating system users must come to a consensus as to
  1544. X
  1545. X
  1546. X
  1547. X
  1548. XStJohns                                                         [Page 4]
  1549. X
  1550. X
  1551. XRFC 931                                                     January 1985
  1552. XAuthentication Server
  1553. X
  1554. X
  1555. X   what the OFFICIAL user identification for their systems will be.
  1556. X   Until they register this information, they must use the "OTHER" tag
  1557. X   to specify their user identification.
  1558. X
  1559. XNotes on User Identification Translation:
  1560. X
  1561. X   Once you have a user identifier from a remote system, you must then
  1562. X   have a way of translating it into an identifier that meaningful on
  1563. X   the local system.  The following is a sketchy outline of table driven
  1564. X   scheme for doing this.
  1565. X
  1566. X   The table consists of four columns, the first three are used to match
  1567. X   against, the fourth is the result.
  1568. X
  1569. X      USERID              Opsys     Address     Result
  1570. X      MCSJ-MITMUL         TAC       26.*.*.*    StJohns
  1571. X      *                   MULTICS   192.5.42.*  =
  1572. X      *                   OTHER     10.0.0.42   anonymous
  1573. X      MSJ                 ITS       10.3.0.44   StJohns
  1574. X
  1575. X   The above table is a sample one for a Multics system on MILNET at the
  1576. X   Pentagon.  When an authentication is returned, the particular
  1577. X   application using the userid simply looks for the first match in the
  1578. X   table.  Notice the second line.  It says that any authentication
  1579. X   coming from a Multics system on Net 192.5.42 is accepted in the same
  1580. X   format.
  1581. X
  1582. X   Obviously, various users will have to be registered to use this
  1583. X   facility, but the registration can be done at the same time the use
  1584. X   receives his login identity from the system.
  1585. X
  1586. X
  1587. X
  1588. X
  1589. X
  1590. X
  1591. X
  1592. X
  1593. X
  1594. X
  1595. X
  1596. X
  1597. X
  1598. X
  1599. X
  1600. X
  1601. X
  1602. X
  1603. X
  1604. XStJohns                                                         [Page 5]
  1605. END_OF_FILE
  1606. if test 9196 -ne `wc -c <'rfc931'`; then
  1607.     echo shar: \"'rfc931'\" unpacked with wrong size!
  1608. fi
  1609. # end of 'rfc931'
  1610. fi
  1611. echo shar: End of archive 2 \(of 2\).
  1612. cp /dev/null ark2isdone
  1613. MISSING=""
  1614. for I in 1 2 ; do
  1615.     if test ! -f ark${I}isdone ; then
  1616.     MISSING="${MISSING} ${I}"
  1617.     fi
  1618. done
  1619. if test "${MISSING}" = "" ; then
  1620.     echo You have unpacked both archives.
  1621.     rm -f ark[1-9]isdone
  1622. else
  1623.     echo You still need to unpack the following archives:
  1624.     echo "        " ${MISSING}
  1625. fi
  1626. ##  End of shell archive.
  1627. exit 0
  1628. exit 0 # Just in case...
  1629.